/*************************************************************************
 *                                                                       *
 * This file is part of the DogosFrame distribution.  For full copyright *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 *                                                                       *
 *************************************************************************/

#ifndef DOGOS_include_COMMON_base_DogosNullPTR_h
#define DOGOS_include_COMMON_base_DogosNullPTR_h

#include "DogosConfig.h"

#if defined(DOGOS_HAVE_CXX11_NULLPTR)

// Use the built-in nullptr keyword
#define DOGOS_NULL_PTR nullptr

#elif defined(DOGOS_HAVE_CXX11_NULLPTR_WORKAROUND)

/**
 * A C++03-compatible nullptr type implemented as a library solution
 * rather than a language keyword.  Originally due to Scott Meyers,
 * Effective C++, 2nd Edition, Item 25.  The main benefits of using
 * this type over NULL are
 * 1.) Expressiveness:
 * 2.) Disambiguating overloads, e.g.
 *     void f(int);
 *     void f(double *);
 *     f(NULL); // ambiguous
 *     f(nullptr); // unambiguous - calls the version of f taking a pointer
 *
 * We are specifically *not* attempting to redefine the 'nullptr'
 * keyword itself -- that can lead to issues when C++11 is disabled,
 * yet the compiler still has 'nullptr' defined.  Therefore, client
 * code that wishes to be more expressive/correct should use
 * 'DOGOS_NULL_PTR' for maximum backwards compatibility.
 *
 * Note: the leading const applies to the following nullptr
 * instance.
 *
 * Code originally coped from:
 * https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/nullptr#Solution_and_Sample_Code
 */
const class DOGOS_NULL_PTR_t
{
public:
  // convertible to any type of null non-member pointer...
  template<class T>
  inline operator T * () const { return 0; }

  // or any type of null member pointer...
  template<class C, class T>
  inline operator T C::*() const { return 0; }

private:
  // Can't take address of nullptr
  void operator & () const;
} DOGOS_NULL_PTR = {};

#else

// No nullptr and workaround doesn't compile.  This should not be
// common, but in this case, We have to fall back on the C++03
// definition of NULL.
#define DOGOS_NULL_PTR NULL

#endif // DOGOS_HAVE_CXX11_NULLPTR

#endif // DOGOS_include_COMMON_base_DogosNullPTR_h
